﻿using Microsoft.Xna.Framework;
using Terraria;
using Terraria.Audio;
using Terraria.GameContent.Bestiary;
using Terraria.ID;
using Terraria.ModLoader;
using Terraria.ModLoader.Utilities;

namespace HardcoreGame.Content.NPCs.Enemies.Variant.Zombies
{
    public class TimeZombie : ModNPC
    {
        private enum AIState
        {
            Normal = 0,
            TimeFreeze = 1,
            TimeRewind = 2,
            Resurrecting = 3
        }

        private struct ZombieState
        {
            public int health;
            public Vector2 position;
            public Vector2 velocity;
            public int defense;
        }
        private ref float AI_State => ref NPC.ai[0];
        private ref float AI_Timer => ref NPC.ai[1];
        private ref float AI_ResurrectCount => ref NPC.ai[2];
        private ref float AI_TimeFreezeCooldown => ref NPC.ai[3];
        private ZombieState savedState;
        private bool isRewinding = false;
        private bool hasSavedState = false;

        public override void SetStaticDefaults()
        {
            Main.npcFrameCount[Type] = Main.npcFrameCount[NPCID.Zombie];
            NPCID.Sets.TrailingMode[Type] = 2;
            NPCID.Sets.TrailCacheLength[Type] = 5;

            NPCID.Sets.NPCBestiaryDrawModifiers value = new()
            {
                Velocity = 1f,
            };
            NPCID.Sets.NPCBestiaryDrawOffset.Add(Type, value);
        }

        public override void SetDefaults()
        {
            AIType = NPCID.Zombie;
            AnimationType = NPCID.Zombie;
            Banner = Item.NPCtoBanner(NPCID.Zombie);
            BannerItem = Item.BannerToItem(Banner);

            NPC.width = 18;
            NPC.height = 40;
            NPC.aiStyle = 3;
            NPC.damage = 18;
            NPC.defense = 8;
            NPC.lifeMax = 35;
            NPC.HitSound = SoundID.NPCHit1;
            NPC.DeathSound = SoundID.NPCDeath2;
            NPC.knockBackResist = 0.3f;
            NPC.value = 250f;
            NPC.buffImmune[BuffID.Slow] = true;
            NPC.buffImmune[BuffID.Confused] = true;
        }

        public override float SpawnChance(NPCSpawnInfo spawnInfo)
        {
            if (spawnInfo.Player.ZoneOverworldHeight && !Main.dayTime)
            {
                return SpawnCondition.OverworldNightMonster.Chance * 0.0003f;
            }
            return 0f;
        }

        public override void SetBestiary(BestiaryDatabase database, BestiaryEntry bestiaryEntry)
        {
            bestiaryEntry.Info.AddRange([
                BestiaryDatabaseNPCsPopulator.CommonTags.SpawnConditions.Times.NightTime,
                new FlavorTextBestiaryInfoElement("Mods.HardcoreGame.Bestiary.TimeZombie"),
            ]);
        }

        public override void AI()
        {
            bool isOnScreen = NPC.Distance(Main.player[NPC.target].Center) < 1000f;

            if (AI_State == (int)AIState.Normal && isOnScreen)
            {
                AI_TimeFreezeCooldown++;
                if (AI_TimeFreezeCooldown >= 900 && Main.rand.NextBool(3))
                {
                    AI_State = (int)AIState.TimeFreeze;
                    AI_Timer = 0;
                    AI_TimeFreezeCooldown = 0;

                    NPC.velocity = Vector2.Zero;
                    for (int i = 0; i < 30; i++)
                    {
                        Dust.NewDust(NPC.position, NPC.width, NPC.height, DustID.Cloud, Scale: 1.5f);
                    }
                    SoundEngine.PlaySound(SoundID.Item8 with { Pitch = 0.5f }, NPC.position);
                }

                if (Main.GameUpdateCount % 180 == 0)
                {
                    SaveZombieState();
                }
            }
            else if (AI_State == (int)AIState.TimeFreeze)
            {
                AI_Timer++;

                if (AI_Timer <= 300)
                {
                    if (AI_Timer % 30 == 0)
                    {
                        for (int i = 0; i < Main.maxPlayers; i++)
                        {
                            Player player = Main.player[i];
                            if (player.active && !player.dead && NPC.Distance(player.Center) < 600f)
                            {
                                player.velocity *= 0f;
                                player.AddBuff(BuffID.Slow, 60);
                                for (int j = 0; j < 5; j++)
                                {
                                    Dust.NewDust(player.position, player.width, player.height, DustID.Cloud, Scale: 1.2f);
                                }
                            }
                        }
                    }
                }
                else
                {
                    AI_State = (int)AIState.Normal;
                }
            }
            if (isRewinding && AI_Timer > 0)
            {
                AI_Timer--;
                if (AI_Timer % 30 == 0)
                {
                    for (int i = 0; i < 10; i++)
                    {
                        Dust.NewDust(NPC.position, NPC.width, NPC.height, DustID.Blood, Scale: 1.2f);
                    }
                }

                if (AI_Timer <= 0)
                {
                    RewindZombieState();
                    isRewinding = false;
                }
            }
            if (AI_State == (int)AIState.Resurrecting)
            {
                AI_Timer--;
                NPC.alpha = (int)(255 * (AI_Timer / 120f));
                NPC.noGravity = true;
                NPC.velocity.Y = -0.5f;

                if (AI_Timer <= 0)
                {
                    AI_State = (int)AIState.Normal;
                    NPC.alpha = 0;
                    NPC.noGravity = false;
                    for (int i = 0; i < 30; i++)
                    {
                        Dust.NewDust(NPC.position, NPC.width, NPC.height, DustID.Blood, Scale: 1.5f);
                    }
                }
            }
        }
        private void SaveZombieState()
        {
            savedState = new ZombieState
            {
                health = NPC.life,
                position = NPC.position,
                velocity = NPC.velocity,
                defense = NPC.defense
            };
            hasSavedState = true;
        }
        private void RewindZombieState()
        {
            if (hasSavedState)
            {
                NPC.life = savedState.health;
                NPC.position = savedState.position;
                NPC.velocity = savedState.velocity;
                NPC.defense = savedState.defense;
                for (int i = 0; i < 30; i++)
                {
                    Dust.NewDust(NPC.position, NPC.width, NPC.height, DustID.Blood, Scale: 1.5f);
                }
                SoundEngine.PlaySound(SoundID.Item8 with { Pitch = -0.5f }, NPC.position);
            }
        }

        public override void ModifyHitByItem(Player player, Item item, ref NPC.HitModifiers modifiers)
        {
            if (Main.rand.NextBool(4) && !isRewinding && hasSavedState)
            {
                isRewinding = true;
                AI_Timer = 150;
                for (int i = 0; i < 15; i++)
                {
                    Dust.NewDust(NPC.position, NPC.width, NPC.height, DustID.GoldCoin, Scale: 1.2f);
                }
                SoundEngine.PlaySound(SoundID.Item7 with { Pitch = 0.5f }, NPC.position);
            }
        }

        public override void ModifyHitByProjectile(Projectile projectile, ref NPC.HitModifiers modifiers)
        {
            if (Main.rand.NextBool(4) && !isRewinding && hasSavedState)
            {
                isRewinding = true;
                AI_Timer = 150;
                for (int i = 0; i < 15; i++)
                {
                    Dust.NewDust(NPC.position, NPC.width, NPC.height, DustID.GoldCoin, Scale: 1.2f);
                }
                SoundEngine.PlaySound(SoundID.Item7 with { Pitch = 0.5f }, NPC.position);
            }
        }

        public override bool CheckDead()
        {
            if (AI_ResurrectCount < 1 && Main.rand.NextBool(3))
            {
                SaveZombieState();
                NPC.life = NPC.lifeMax / 2;
                AI_ResurrectCount++;
                AI_State = (int)AIState.Resurrecting;
                AI_Timer = 120;
                return false;
            }

            return base.CheckDead();
        }

        public override void HitEffect(NPC.HitInfo hit)
        {
            if (NPC.life > 0)
            {
                for (int i = 0; i < 10; i++)
                {
                    Dust.NewDust(NPC.position, NPC.width, NPC.height, DustID.Blood, hit.HitDirection, -1f);
                }

                if (Main.rand.NextBool(3))
                {
                    Dust.NewDust(NPC.position, NPC.width, NPC.height, DustID.Blood, Scale: 1.2f);
                }
            }
            else if (AI_State != (int)AIState.Resurrecting)
            {
                for (int i = 0; i < 30; i++)
                {
                    Dust.NewDust(NPC.position, NPC.width, NPC.height, DustID.Blood, 2.5f * hit.HitDirection, -2.5f, 0, default, 0.7f);
                }
                if (Main.netMode != NetmodeID.Server)
                {
                    Gore.NewGore(NPC.GetSource_Death(), NPC.position, NPC.velocity, Mod.Find<ModGore>("Gore_10").Type, 1f);
                    Gore.NewGore(NPC.GetSource_Death(), NPC.position, NPC.velocity, 3);
                    Gore.NewGore(NPC.GetSource_Death(), NPC.position, NPC.velocity, 4);
                    Gore.NewGore(NPC.GetSource_Death(), NPC.position, NPC.velocity, 5);
                }
            }
        }

        public override void ModifyNPCLoot(NPCLoot npcLoot)
        {
            var zombieDropRules = Main.ItemDropsDB.GetRulesForNPCID(NPCID.Zombie, false);
            foreach (var zombieDropRule in zombieDropRules)
            {
                npcLoot.Add(zombieDropRule);
            }

        }
    }
}